package logger

import (
	"os"

	"github.com/gin-gonic/gin"
	"go.uber.org/zap"
	"go.uber.org/zap/zapcore"
	"gopkg.in/natefinch/lumberjack.v2"
)

// LoggerUtil 是日志工具类
type LoggerUtil struct {
	logger *zap.Logger
}

// NewLoggerUtil 创建一个新的 LoggerUtil 实例
func NewLoggerUtil() *LoggerUtil {
	// 检查日志文件目录是否存在，不存在则创建
	if _, err := os.Stat("./logs"); os.IsNotExist(err) {
		err := os.MkdirAll("./logs", 0755)
		if err != nil {
			panic(err)
		}
	}
	// 创建 lumberjack 写入器，设置日志文件切割规则
	lumberJackLogger := &lumberjack.Logger{
		Filename:   "./logs/app.log", // 日志文件路径
		MaxSize:    2,                // 单个日志文件最大大小（MB）
		MaxBackups: 5,                // 最多保留的旧日志文件数量
		MaxAge:     30,               // 旧日志文件最多保留的天数
		Compress:   true,             // 是否压缩旧日志文件
	}

	// 配置日志编码器
	encoderConfig := zapcore.EncoderConfig{
		TimeKey:        "time",
		LevelKey:       "level",
		NameKey:        "logger",
		CallerKey:      "caller",
		MessageKey:     "msg",
		StacktraceKey:  "stacktrace",
		LineEnding:     zapcore.DefaultLineEnding,
		EncodeLevel:    zapcore.CapitalLevelEncoder,
		EncodeTime:     zapcore.ISO8601TimeEncoder,
		EncodeDuration: zapcore.SecondsDurationEncoder,
		EncodeCaller:   zapcore.ShortCallerEncoder,
	}

	// 创建日志核心
	fileCore := zapcore.NewCore(
		zapcore.NewJSONEncoder(encoderConfig),
		zapcore.AddSync(lumberJackLogger),
		zap.InfoLevel,
	)
	// 创建控制台核心
	consoleCore := zapcore.NewCore(
		zapcore.NewConsoleEncoder(encoderConfig),
		zapcore.AddSync(os.Stdout),
		zap.DebugLevel,
	)
	combinedCore := zapcore.NewTee(fileCore, consoleCore)
	// 创建 zap 日志记录器
	logger := zap.New(combinedCore, zap.AddCaller())

	return &LoggerUtil{
		logger: logger,
	}
}

// Info 记录信息级别的日志
func (l *LoggerUtil) Info(msg string, fields ...zap.Field) {
	l.logger.Info(msg, fields...)
}

// Error 记录错误级别的日志
func (l *LoggerUtil) Error(msg string, fields ...zap.Field) {
	l.logger.Error(msg, fields...)
}

// Sync 同步日志缓存
func (l *LoggerUtil) Sync() error {
	return l.logger.Sync()
}

// GetLoggerFromContext 从 Gin 上下文中获取 loggerUtil 实例
func (l *LoggerUtil) GetLoggerFromContext(c *gin.Context) *LoggerUtil {
	logger, exists := c.Get("loggerUtil")
	if !exists {
		return nil
	}
	return logger.(*LoggerUtil)
}
